#ifndef LAURIN_MODULE_H_
#define LAURIN_MODULE_H_

#include "laurin-module-handler.h"
#include <glibmm/ustring.h>
#include <glibmm/quark.h>
#include <glibmm/thread.h>


/**
 * Class that represent a module for the Laurin Project.
 * It's a thread and stop/start procedure are implemented in a thread-safe manner.
 * Each subclass  must override at least these two methods:
 *
 * 1) run(): this method will be called after the start() call. Here we can implement the module logic.
 * 2) innerStop(): this method will be called whenever stop() method is called.
 *
 *
 *
 * On run() we can't call blocking function, otherwise the stop() method is broken.
 *
 *
 */
class LaurinModule
{
	public:

		virtual ~LaurinModule();
		bool operator=(const LaurinModule& op);

		Glib::ustring getModuleName() const;
		Glib::ustring getErrorMessage() const;

		bool stop(bool wait = false);
		bool start();

		/**
		 * Is module working?
		 * Thread safe call.
		 */
		bool isWorking();



	protected:

		LaurinModule(const Glib::ustring& moduleName, LaurinModuleHandler* handler);

		/**
		 * Return true if a stop() call is made. False otherwise.
		 * It's useful if on run() we have implemented some kind of loop and we need to know at each iteration
		 * if a stop request was made during the loop body.
		 *
		 * Is a thread-safe call.
		 */
		bool isStopRequestPending();

		virtual bool run() = 0;
		virtual void innerStop();


		Glib::ustring _errmess;

	private:


		void setActive();				// defers the creation of the thread only when really need.
		void wait();					// pause the thread, only internal
		void wakeup();					// wake up the sleeping thread


		LaurinModuleHandler* _handler;
		Glib::Quark* _id;
		Glib::ustring _module_name;
		Glib::Mutex _mutex;
		Glib::Cond _wait;
		Glib::Cond _stop_wait;
		Glib::Thread* _thread;

		bool _wakeup;					// is thread sleeping? (different from working!)
		bool _created;					// check if thread is created.
		bool _exit;						// for exiting purpose
		bool _working;					// is thread working?
		bool _stop_request;				// is stop request pending?
};

#endif
